﻿using System;
using System.Collections.Generic;
using NHibernate.Mapping.ByCode;
using Xenta.Enums;
using Xenta.Utils;

namespace Xenta.Entities
{
    /// <summary>
    /// Represents the sales rule entity.
    /// </summary>
    public abstract class SalesRuleEntity : AuditableEntity,
        IRelationHolder<RoleEntity>
    {
        #region Fields

        private DateTime _validFrom;
        private DateTime _validTo;
        private ICollection<SalesRuleHistoryEntity> _history;
        private ICollection<RoleEntity> _roles;

        #endregion

        #region Ctors

        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        protected SalesRuleEntity()
        {
            _validFrom = DateTime.UtcNow;
            _validTo = DateTime.UtcNow.AddMonths(1);
            _history = new List<SalesRuleHistoryEntity>();
            _roles = new List<RoleEntity>();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the global unique identifier of a rule handler.
        /// </summary>
        public abstract Guid HandlerID
        {
            get;
        }

        /// <summary>
        /// Gets the a rule priority.
        /// </summary>
        /// <remarks>
        /// The default priority value is 100.
        /// </remarks>
        public virtual int Priority
        {
            get
            {
                return 100;
            }
        }

        /// <summary>
        /// Gets the rule system code.
        /// </summary>
        public abstract string Code
        {
            get;
        }

        /// <summary>
        /// Gets or sets the rule name.
        /// </summary>
        public virtual string Name
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the common flags.
        /// </summary>
        public virtual SalesRuleFlags CommonFlags
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the validity date 'from'.
        /// </summary>
        public virtual DateTime ValidFrom
        {
            get
            {
                return _validFrom;
            }
            set
            {
                _validFrom = value;
            }
        }

        /// <summary>
        /// Gets or sets the validity date 'to'.
        /// </summary>
        public virtual DateTime ValidTo
        {
            get
            {
                return _validTo;
            }
            set
            {
                _validTo = value;
            }
        }

        #endregion

        #region Collections

        /// <summary>
        /// Gets or sets the rule history.
        /// </summary>
        public virtual ICollection<SalesRuleHistoryEntity> History
        {
            get
            {
                return _history;
            }
            set
            {
                _history = value;
            }
        }

        /// <summary>
        /// Gets or sets the roles.
        /// </summary>
        public virtual ICollection<RoleEntity> Roles
        {
            get
            {
                return _roles;
            }
            set
            {
                _roles = value;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Maps a role to the rule.
        /// </summary>
        /// <param name="child">The role to map.</param>
        public virtual void Map(RoleEntity child)
        {
            if(Roles.Contains(child))
                return;
            Roles.Add(child);
        }

        /// <summary>
        /// Unmaps the role from the rule.
        /// </summary>
        /// <param name="child">The role to unmap.</param>
        public virtual void Unmap(RoleEntity child)
        {
            if(!Roles.Contains(child))
                return;
            Roles.Remove(child);
        }

        #endregion

        #region Utilities

        protected override void Disclose(IDictionary<String, Object> obj,
            DisclosureLevel level,
            IDictionary<String, String> options)
        {
            base.Disclose(obj, level, options);
            if(level >= DisclosureLevel.Base)
            {
                obj["Code"] = Code;
                obj["Name"] = Name;
                obj["CommonFlags"] = CommonFlags.ToString();
                obj["ValidFrom"] = ValidFrom;
                obj["ValidTo"] = ValidTo;
            }
            if(level >= DisclosureLevel.Entire)
                obj["Roles"] = Roles.Map(x => x.Disclose(DisclosureLevel.Base, options));
        }

        #endregion
    }

    /// <summary>
    /// The entity NHibernate mapping.
    /// </summary>
    public class SalesRuleMapping : EntityMapping<SalesRuleEntity>
    {
        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public SalesRuleMapping()
        {
            Table("fwk_SalesRules");
            Id(x => x.EntityID, m =>
            {
                m.Column("RuleID");
                m.Generator(Generators.Identity);
            });
            Property(x => x.Name, m =>
            {
                m.NotNullable(true);
                m.Length(100);
                m.Column(c =>
                {
                    c.SqlType("nvarchar(100)");
                });
            });
            Property(x => x.CommonFlags, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.ValidFrom, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.ValidTo, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.CreatedOn, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.UpdatedOn, m =>
            {
                m.NotNullable(true);
            });
            Bag(x => x.History, m =>
            {
                m.Table("fwk_SalesRuleHistory");
                m.Key(k =>
                {
                    k.Column("RuleID");
                    k.ForeignKey("FK_fwk_SalesRuleHistory_fwk_SalesRules");
                    k.NotNullable(true);
                });
                m.Inverse(true);
            },
            a =>
            {
                a.OneToMany();
            });
            Bag(x => x.Roles, m =>
            {
                m.Table("fwk_MSalesRuleRoles");
                m.Key(k =>
                {
                    k.Column("RuleID");
                    k.ForeignKey("FK_fwk_MSalesRuleRoles_fwk_SalesRules");
                    k.NotNullable(true);
                });
            },
            a =>
            {
                a.ManyToMany(m =>
                {
                    m.Column("RoleID");
                    m.ForeignKey("FK_fwk_MSalesRuleRoles_fwk_Roles");
                });
            });
        }
    }
}
